import 'dart:math';

import 'package:built_collection/built_collection.dart';
import 'package:mobile_app.core/core/domain/entities/learning_content/lexical_item/lexical_item.dart';

abstract class PickUnspecifiedLexicalItem {
  LexicalItem? call({
    required BuiltMap<String, LexicalItem> lexicalItemMap,
    required BuiltSet<String> unspecifiedLexicalItemIds,
    required BuiltSet<String> highPriorityLexicalItemIds,
    required String? lastUnspecifiedLexicalItemId,
    required String? lastSkippedUnspecifiedLexicalItemId,
  });
}

class PickUnspecifiedLexicalItemImpl implements PickUnspecifiedLexicalItem {
  const PickUnspecifiedLexicalItemImpl();

  @override
  LexicalItem? call({
    required BuiltMap<String, LexicalItem> lexicalItemMap,
    required BuiltSet<String> unspecifiedLexicalItemIds,
    required BuiltSet<String> highPriorityLexicalItemIds,
    required String? lastUnspecifiedLexicalItemId,
    required String? lastSkippedUnspecifiedLexicalItemId,
  }) {
    if (unspecifiedLexicalItemIds.isEmpty) {
      return null;
    }

    if (lastUnspecifiedLexicalItemId != null) {
      final lexicalItem = lexicalItemMap[lastUnspecifiedLexicalItemId];

      if (lexicalItem != null &&
          !lexicalItem.excluded &&
          lexicalItem.isUnspecified &&
          lexicalItem.id != lastSkippedUnspecifiedLexicalItemId &&
          unspecifiedLexicalItemIds.contains(lastUnspecifiedLexicalItemId)) {
        return lexicalItem;
      }
    }

    var lastSkippedUnspecifiedLexicalItemAvailable = false;

    if (lastSkippedUnspecifiedLexicalItemId != null) {
      lastSkippedUnspecifiedLexicalItemAvailable =
          unspecifiedLexicalItemIds.contains(lastSkippedUnspecifiedLexicalItemId);
    }

    final unspecifiedHighPriorityLexicalItemIds =
        unspecifiedLexicalItemIds.intersection(highPriorityLexicalItemIds).toSet();

    final Set<String> pickableLexicalItemIds;

    if (unspecifiedHighPriorityLexicalItemIds.isEmpty) {
      pickableLexicalItemIds = unspecifiedLexicalItemIds.toSet();
    } else {
      pickableLexicalItemIds = unspecifiedHighPriorityLexicalItemIds;
    }

    if (pickableLexicalItemIds.length > 1 && lastSkippedUnspecifiedLexicalItemAvailable) {
      pickableLexicalItemIds.remove(lastSkippedUnspecifiedLexicalItemId);
    }

    final index = Random().nextInt(pickableLexicalItemIds.length);
    final pickedLexicalItemId = pickableLexicalItemIds.toList()[index];

    return lexicalItemMap[pickedLexicalItemId]!;
  }
}
